<?php

namespace app\admin\services;

use app\admin\model\AdminModel;
use app\admin\validate\AdminValidate;
use app\event\UserLogin;
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
use Firebase\JWT\SignatureInvalidException;
use think\Cache;
use think\exception\ValidateException;

/**
 * admin service
 * Class AdminService
 * @package app\admin\services
 */
class AdminService extends BaseService
{
    protected $key;
    /**
     * 模型注入
     * SystemAdminServices constructor.
     * @param AdminModel $model
     */
    public function __construct(AdminModel $model, Cache $cache)
    {
        $this->model = $model;
        $this->cache = $cache;
        $this->key = md5('zy0714!@!');
    }

    /**
     * 管理员登陆
     * @param string $account
     * @param string $password
     * @return mixed
     */
    public function verifyLogin(string $account, string $password)
    {
        $cacheUserLoginError = $this->cache->store("duration")->get($account . $_SERVER['REMOTE_ADDR']); //有限制的时长
        if ($cacheUserLoginError) {
            api_return(20007);
        }
        $userLoginFailNum = $this->cache->store("duration")->get($account . "LOGIN_FAIL_NUM");  //失败次数
//        var_dump($userLoginFailNum);die;
//        if (intval($userLoginFailNum) >= env("LOGIN.FAIL_NUM")) {
//            $this->cache->store("duration")->set($account . $_SERVER['REMOTE_ADDR'], 1, env("LOGIN.FAIL_EXPIRE"));
//            $this->cache->store("duration")->delete($account . "LOGIN_FAIL_NUM");
//            api_return(20007);
//        }
        $adminInfo = $this->model->accountByAdmin($account);
        if (!$adminInfo) {
            $userLoginFailNum = $userLoginFailNum + 1;
            $this->cache->store("duration")->set($account . "LOGIN_FAIL_NUM", $userLoginFailNum);
            event(new UserLogin($account, 20001, 1));
            api_return(20001);   //用户无效
        }
        if (!$adminInfo->status) {
            event(new UserLogin($account, 20005, 1));
            api_return(20005);
        }
        if (!password_verify($password, $adminInfo->pwd)) {
            $userLoginFailNum = $userLoginFailNum + 1;
            $this->cache->store("duration")->set($account . "LOGIN_FAIL_NUM", $userLoginFailNum);
            event(new UserLogin($account, 20004, 1));
            api_return(20004);
        }
//
        $adminInfo->last_login_time = time();
        $adminInfo->last_ip = app('request')->ip();     //获取IP地址
        $adminInfo->login_count++;
        $adminInfo->save();
        event(new UserLogin($account, 200, 1));
        return $adminInfo;
    }

    /**
     * 管理员手机号登录
     * @param $phone
     * @return mixed
     */
    public function verifyMobileLogin($phone)
    {
        $adminInfo = $this->model->mobileByAdmin($phone);
        if (!$adminInfo) {
            event(new UserLogin($phone, 20001, 2));
            api_return(20001);
        }

        $adminInfo->last_time = time();
        $adminInfo->last_ip = app('request')->ip();     //获取IP地址
        $adminInfo->login_count++;
        $adminInfo->save();
        event(new UserLogin($phone, 200, 2));
        return $adminInfo;
    }

    /**
     * 后台登陆获取用户信息,获取token
     * @param string $account
     * @param string $password
     * @return array
     */
    public function login(string $account, string $password)
    {
        $adminInfo = $this->verifyLogin($account, $password);
        $returnAdminInfo = [
            "id" => $adminInfo->id,
            "account" => $adminInfo->account,
            "head_pic" => $adminInfo->head_pic,
            'area'=>$adminInfo->area
        ];
        //缓存管理员数据
        $this->cache->store("userInfo")->set("ADMIN_USERINFO_" . $adminInfo->id, $returnAdminInfo);
        $tokenInfo = $this->createToken($adminInfo->id);
        return [
            'token' => $tokenInfo??"",
            'admin_info' => $returnAdminInfo??[],
        ];
    }

    /**
     * 密码规则
     * @param $key
     * @return mixed
     */
    public function getPassWordEnv()
    {
        $getPassWordConfig = env("LOGIN.LOGIN_PASSWORD_CASE", 4);
        $length = env("LOGIN_PASSWORD_LENGTH_MIN", 6);
        $PASSWORD_RULE = [
            1 => "require|number|min:" . $length,       //纯数字
            2 => "require|alpha|min:" . $length,        //纯字母 包含大小写字母
            3 => "require|alphaDash|min:" . $length,   //字母和数字，下划线_及破折号-
            4 => "require|min:" . $length,  //字符串即可
        ];

        $PASSWORD_ERROR_MSG = [
            1 => ['pwd.number' => "密码是纯数字", 'pwd.min' => "密码最少为{$length}位"],
            2 => ['pwd.alpha' => "密码是包含大小写的纯字母", 'pwd.min' => "密码最少为{$length}位"],
            3 => ['pwd.alphaDash' => "密码是包含字母和数字，下划线_及破折号-", 'pwd.min' => "密码最少为{$length}位"],
            4 => ['pwd.min' => "密码最少为{$length}位"],
        ];
        return [$PASSWORD_RULE[$getPassWordConfig], $PASSWORD_ERROR_MSG[$getPassWordConfig]];
    }

    /**
     * 检查字段规则
     * @param $account
     * @param $password
     * @return bool
     */
    public function checkParamRule($account, $password)
    {
        list($passwordRule, $passwordErrorMsg) = $this->getPassWordEnv();
        try {
            validate(AdminValidate::class)->append("pwd", $passwordRule)->message($passwordErrorMsg)->check(['account' => $account, 'pwd' => $password]);
        } catch (ValidateException $e) {
            api_return(50001, $e->getMessage());
        }
        return true;
    }

    /**
     * 手机登录
     * @param string $account
     * @param string $password
     * @return array
     */
    public function mobileLogin($phone, $code)
    {
        if ($this->cache->store("mobile")->get("ADMIN_MOBILE_CODE_" . $phone) != $code) {
            event(new UserLogin($phone, 20006, 2));
            api_return(20006);
        }

        $adminInfo = $this->verifyMobileLogin($phone);
        $returnAdminInfo = [
            "id" => $adminInfo->id,
            "account" => $adminInfo->account,
            "head_pic" => $adminInfo->head_pic,
        ];
        //缓存管理员数据
        $this->cache->store("userInfo")->set("ADMIN_USERINFO_" . $adminInfo->id, $returnAdminInfo);
        $tokenInfo = $this->createToken($adminInfo->id);
        return [
            'token' => $tokenInfo??"",
            'admin_info' => $returnAdminInfo??[],
        ];
    }

    /**
     * 发送验证码
     * @param $phone
     * @return int
     */
    public function sendPhoneSms($phone)
    {
        $mobileLimit = $this->cache->store("mobile")->get("ADMIN_MOBILE_" . $phone);
        if ($mobileLimit) {
            api_return(20008);
        }
        $code = rand(100000, 999999);
        $this->cache->store("mobile")->set("ADMIN_MOBILE_CODE_" . $phone, $code, env("MOBILE.MOBILE_EXPIRE"));     //缓存5分钟
        if (env("MOBILE.MOBILE_LIMIT") > 0) {
            $this->cache->store("mobile")->set("ADMIN_MOBILE_" . $phone, 1, env("MOBILE.MOBILE_LIMIT"));
        }

        return $code;
    }

    /**
     * 创建token
     * @param int $id
     * @return array
     */
    public function createToken(int $uid)
    {
        $time = time(); //签发时间
        $expire = $time + env("LOGIN.LOGIN_EXPIRE_TIMEOUT"); //过期时间
        $token = array(
            "user_id" => $uid,
            "iss" => "panguwangluo",//签发组织
            "aud" => "zhangyu",
            "iat" => $time,
            "nbf" => $time,
            "exp" => $expire
        );
        return JWT::encode($token, $this->key, "HS256");
    }

    /**
     * 解析token
     * @param string $jwt
     * @return bool
     */
    public function parseToken(string $jwt)
    {
        try {
//            JWT::$leeway = 10;
            $jwtAuth = json_encode(JWT::decode($jwt, new Key($this->key, "HS256")));
            $authInfo = json_decode($jwtAuth, true);
            $result = false;
            if (!empty($authInfo['user_id'])) {
                $result = $authInfo['user_id'];
            }
            return $result;
        } catch (\Firebase\JWT\ExpiredException $e) {
            api_return(20002, "登录超时，请重新登录");
            exit;
        } catch (SignatureInvalidException $e) {
            api_return(20002, $e->getMessage());
            exit;
        } catch (\Exception $e) {
            api_return(20002, $e->getMessage());
            exit;
        }
    }


    /**
     * 是否需要修改密码
     * @param int $uid
     * @return bool
     */
    public function pwdExpire(int $uid)
    {
        $pwdExpire = $this->model->pwdExpire($uid);
        return !empty(env("LOGIN.PWD_EXPIRE")) && $pwdExpire + intval(env("LOGIN.PWD_EXPIRE")) > time() ? true : false;
    }
}
